package com.wteam.dragon.model.service.impl;

import cn.hutool.core.lang.Dict;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wteam.dragon.model.mapper.*;
import com.wteam.dragon.model.pojo.bean.*;
import com.wteam.dragon.model.pojo.dto.RoleDto;
import com.wteam.dragon.model.pojo.dto.RoleSmallDto;
import com.wteam.dragon.model.pojo.dto.UserDto;
import com.wteam.dragon.model.service.RoleService;
import com.wteam.dragon.system.basebean.bean.ResultMessage;
import com.wteam.dragon.system.exception.BadRequestException;
import com.wteam.dragon.system.util.StringUtils;
import com.wteam.dragon.system.util.UserUtil;
import com.wteam.dragon.system.util.ValidationUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 陈晓辉
 * @Date 2020/4/2 9:38
 */
@Service
@CacheConfig(cacheNames = "role")
@RequiredArgsConstructor
public class RoleServiceImpl implements RoleService {
    private final RoleMapper roleMapper;
    private final RolesMenusMapper rolesMenusMapper;
    private final MenuMapper menuMapper;
    private final UsersRolesMapper usersRolesMapper;
    private final RoleSmallDtoMapper roleSmallDtoMapper;
    private final RolesDeptsMapper rolesDeptsMapper;
    private final DeptMapper deptMapper;
    private final RoleDtoMapper roleDtoMapper;
    private final UserMapper userMapper;

    @Override
    public List<RoleSmallDto> getRolesByUserId(Long userId) {
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UsersRoles::getUserId, userId);
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(queryWrapper);
        List<RoleSmallDto> roleSmallDtoList = new ArrayList<>();
        usersRolesList.forEach((usersRoles) -> {
            roleSmallDtoList.add(roleSmallDtoMapper.selectById(usersRoles.getRoleId()));
        });
        return roleSmallDtoList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage addRole(Role role) {
        checkLevel(role.getLevel());
        QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Role::getName, role.getName());
        Role oneRole = roleMapper.selectOne(queryWrapper);
        if (oneRole != null) {
            throw new BadRequestException("名字已经存在");
        }
        roleMapper.insert(role);
        for (Long deptId : role.getDeptIds()) {
            RolesDepts rolesDepts = new RolesDepts();
            rolesDepts.setDeptId(deptId);
            rolesDepts.setRoleId(role.getId());
            rolesDeptsMapper.insert(rolesDepts);
        }
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("添加成功");
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage delRole(Long roleId) {
        //等级等级不足不可以删除角色
        Role role = roleMapper.selectById(roleId);
        checkLevel(role.getLevel());
        checkLevel(role.getLevel());
        //删除角色的时候如果角色有用户关联，不能删除
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UsersRoles::getRoleId, roleId);
        Integer count = usersRolesMapper.selectCount(queryWrapper);
        if (!count.equals(0)) {
            throw new BadRequestException("有用户关联该角色，不能删除该角色");
        }
        roleMapper.deleteById(roleId);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("删除成功");
        return resultMessage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultMessage editRole(Role role) {
        Role oneRole = roleMapper.selectById(role.getId());
        checkLevel(oneRole.getLevel());
        QueryWrapper<RolesDepts> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(RolesDepts::getRoleId, role.getId());
        rolesDeptsMapper.delete(queryWrapper);
        for (Long deptId : role.getDeptIds()) {
            RolesDepts rolesDepts = new RolesDepts();
            rolesDepts.setDeptId(deptId);
            rolesDepts.setRoleId(role.getId());
            rolesDeptsMapper.insert(rolesDepts);
        }
        roleMapper.updateById(role);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setMessage("更新成功");
        return resultMessage;
    }

    @Override
    public ResultMessage listRole(String roleName) {
        QueryWrapper<RoleDto> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .like(roleName != null, RoleDto::getName, roleName)
                .orderByAsc(RoleDto::getLevel);
        List<RoleDto> roleList = roleDtoMapper.selectList(queryWrapper);
        Dict resultMap = new Dict()
                .set("message", "请求成功")
                .set("roleList", roleList);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    public ResultMessage treeRole() {
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Menu::getPid, 0)
                .orderByAsc(Menu::getSort);
        List<Menu> menuList = menuMapper.selectList(queryWrapper);
        List<Map<String, Object>> roleTree = treeRole(menuList);
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("roleTree", roleTree);
        ResultMessage resultMessage = new ResultMessage();
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    public List<Map<String, Object>> treeRole(List<Menu> menus) {
        List<Map<String, Object>> list = new LinkedList<>();
        menus.forEach(
                menu -> {
                    if (menu != null) {
                        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
                        queryWrapper.lambda()
                                .eq(Menu::getPid, menu.getId())
                                .orderByAsc(Menu::getSort);
                        List<Menu> menuList = menuMapper.selectList(queryWrapper);
                        Map<String, Object> map = new HashMap<>(16);
                        map.put("id", menu.getId());
                        map.put("label", menu.getTitle());
                        if (menuList != null && menuList.size() != 0) {
                            map.put("children", treeRole(menuList));
                        }
                        list.add(map);
                    }
                }
        );
        return list;
    }

    @Cacheable(value = "Authorities", key = "'loadPermissionByUser:' + #userDto.username")
    @Override
    public List<GrantedAuthority> mapToGrantedAuthorities(UserDto userDto) {
        Set<Role> roles = new HashSet<>();
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UsersRoles::getUserId, userDto.getId());
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(queryWrapper);
        for (UsersRoles usersRoles : usersRolesList) {
            roles.add(roleMapper.selectById(usersRoles.getRoleId()));
        }
        Set<Menu> menuSet;
        if (roles.size() == 0) {
            throw new BadRequestException("用户需要一个角色");
        }
        for (Role role : roles) {
            QueryWrapper<RolesMenus> rolesMenusQueryWrapper = new QueryWrapper<>();
            rolesMenusQueryWrapper.lambda().eq(RolesMenus::getRoleId, role.getId());
            List<RolesMenus> rolesMenusList = rolesMenusMapper.selectList(rolesMenusQueryWrapper);
            menuSet = new HashSet<>();
            for (RolesMenus rolesMenus : rolesMenusList) {
                Menu menu = menuMapper.selectById(rolesMenus.getMenuId());
                if (menu != null) {
                    menuSet.add(menu);
                }
            }
            role.setMenus(menuSet);
        }
        Set<String> permissions = roles.stream().map(Role::getPermission).filter(StringUtils::isNotBlank).collect(Collectors.toSet());
        permissions.addAll(
                roles.stream().flatMap(role -> role.getMenus().stream())
                        .map(Menu::getPermission)
                        .filter(StringUtils::isNotBlank).collect(Collectors.toSet())
        );
        return permissions.stream().map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
    }

    /**
     * 检查用户权限 (将传进去的等级与当前用户等级进行比较)
     *
     * @param level
     * @return
     */
    public void checkLevel(Integer level) {
        //获得当前用户的最高等级
        User currentUser = userMapper.selectById(UserUtil.getCurrentUserId());
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UsersRoles::getUserId, currentUser.getId());
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(queryWrapper);
        Optional<Integer> currentMax = usersRolesList.stream()
                .map(usersRoles -> roleSmallDtoMapper.selectById(usersRoles.getRoleId()))
                .map(RoleSmallDto::getLevel).min(Comparator.naturalOrder());

        if (!currentMax.isPresent()) {
            throw new BadRequestException("您属于无角色用户,不可以进行任何操作");
        }
        //进行比较
        if (currentMax.get().compareTo(level) >= 0) {
            throw new BadRequestException("权限级别不足，您的权限级别" + currentMax.get() + "低于等于权限级别" + level);
        }
    }

    @Override
    public ResultMessage getRole(Long id) {
        ValidationUtil.isNull("id不能为空", id);
        RoleDto roleDto = roleDtoMapper.selectById(id);
        Set<Menu> menuSet = new HashSet<>();
        QueryWrapper<RolesMenus> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(RolesMenus::getRoleId, roleDto.getId());
        List<RolesMenus> rolesMenusList = rolesMenusMapper.selectList(queryWrapper);
        rolesMenusList.forEach(rolesMenus -> {
            menuSet.add(menuMapper.selectById(rolesMenus.getMenuId()));
        });
        //获得部门
        Set<Dept> deptSet = new HashSet<>();
        QueryWrapper<RolesDepts> rolesDeptsQueryWrapper = new QueryWrapper<>();
        rolesDeptsQueryWrapper.lambda().eq(RolesDepts::getRoleId, roleDto.getId());
        List<RolesDepts> rolesDeptsList = rolesDeptsMapper.selectList(rolesDeptsQueryWrapper);
        rolesDeptsList.forEach(rolesDepts -> {
            deptSet.add(deptMapper.selectById(rolesDepts.getDeptId()));
        });
        roleDto.setMenus(menuSet);
        roleDto.setDepts(deptSet);
        ResultMessage resultMessage = new ResultMessage();
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("roleDto", roleDto);
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }

    @Override
    public ResultMessage getCurrentRole() {
        Long currentUserId = UserUtil.getCurrentUserId();
        QueryWrapper<UsersRoles> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UsersRoles::getUserId, currentUserId);
        List<UsersRoles> usersRolesList = usersRolesMapper.selectList(queryWrapper);
        List<Menu> menuList = new ArrayList<>();
        usersRolesList.forEach(usersRoles -> {
            RoleDto roleDto = roleDtoMapper.selectById(usersRoles.getRoleId());
            Set<Menu> menuSet = new HashSet<>();
            QueryWrapper<RolesMenus> rolesMenusQueryWrapper = new QueryWrapper<>();
            rolesMenusQueryWrapper.lambda().eq(RolesMenus::getRoleId, roleDto.getId());
            List<RolesMenus> rolesMenusList = rolesMenusMapper.selectList(rolesMenusQueryWrapper);
            rolesMenusList.forEach(rolesMenus -> {
                menuSet.add(menuMapper.selectById(rolesMenus.getMenuId()));
            });
            menuList.addAll(menuSet);
        });
        List<Long> menuIdList = menuList.stream().map(Menu::getId).collect(Collectors.toList());
        ResultMessage resultMessage = new ResultMessage();
        Dict resultMap = Dict.create()
                .set("message", "请求成功")
                .set("menuIdList", menuIdList);
        resultMessage.setStatus(HttpStatus.OK.value());
        resultMessage.setResultParam(resultMap);
        return resultMessage;
    }
}
